#include "ManejadorEleccion.h"

using namespace Manejadores;

ManejadorEleccion::ManejadorEleccion() {
	Configuracion* config = Configuracion::getInstancia();
	string pathDeDatos = config->getNombreArchivoEleccion();
	this->elecciones = new ArchivoDeEstructurasVariables(pathDeDatos);
	string indicePorUnicidadHash;
	this->indicePorUnicidad = new HashExtensible("IndicePorUnicidadElecciones");
	this->indicePorDistritoYFecha = new ArbolBMas("IndiceEleccionPorDistritoYFecha");
}

bool ManejadorEleccion::alta(Eleccion* eleccion) {
	string claveFecha = Utils::convertirEnteroAString(eleccion->getFecha());
	string claveCargo = eleccion->getCargo()->getNombre();
	string claveDeUnicidad = claveFecha + claveCargo;
	if (!indicePorUnicidad->existe(claveDeUnicidad)) {
		unsigned int posicionDelRegistro = elecciones->insertar(eleccion);
		indicePorUnicidad->insertar(claveDeUnicidad, posicionDelRegistro);

		for (unsigned int i = 0; i < eleccion->getDistritos()->size(); i++) {
			string claveDistrito = eleccion->getDistritos()->at(i)->getNombre();
			string claveDeDistritoYFecha = claveFecha + claveDistrito;
			indicePorDistritoYFecha->insertar(claveDeDistritoYFecha, posicionDelRegistro);
		}

		indicePorDistritoYFecha->exportar("IndiceEleccionPorDistritoYFecha");
		indicePorUnicidad->exportarTxt("IndicePorUnicidadElecciones");
		return true;
	} else
		return false;
}

bool ManejadorEleccion::baja(Eleccion* eleccion) {
	string claveFecha = Utils::convertirEnteroAString(eleccion->getFecha());
	string claveCargo = eleccion->getCargo()->getNombre();
	string claveDeUnicidad = claveFecha + claveCargo;

	IRegistroIndice* aBorrar = indicePorUnicidad->buscar(claveDeUnicidad);
	if (aBorrar->getOffsets()->size() > 0) {

		elecciones->leer(eleccion, aBorrar->getOffsets()->at(0));
		elecciones->borrar(eleccion, aBorrar->getOffsets()->at(0));
		indicePorUnicidad->eliminar(claveDeUnicidad, aBorrar->getOffsets()->at(0));

		for (unsigned int i = 0; i < eleccion->getDistritos()->size(); i++) {
			string claveDistrito = eleccion->getDistritos()->at(i)->getNombre();
			string claveDeDistritoYFecha = claveFecha + claveDistrito;
			indicePorDistritoYFecha->suprimir(claveDeDistritoYFecha, aBorrar->getOffsets()->at(0));
		}

		indicePorDistritoYFecha->exportar("IndiceEleccionPorDistritoYFecha");
		indicePorUnicidad->exportarTxt("IndicePorUnicidadElecciones");
		return true;
	} else
		return false;
}

bool ManejadorEleccion::modificacion(Eleccion* eleccionAModificar, Eleccion* eleccionModificada) {

	string claveDeUnicidadDeEleccionAModificar = Utils::convertirEnteroAString(eleccionAModificar->getFecha())
			+ eleccionAModificar->getCargo()->getNombre();
	string claveDeUnicidadDeEleccionModificada = Utils::convertirEnteroAString(eleccionModificada->getFecha())
			+ eleccionModificada->getCargo()->getNombre();
	IRegistroIndice* registroEleccionAModificar = indicePorUnicidad->buscar(claveDeUnicidadDeEleccionAModificar);

	if (registroEleccionAModificar->getOffsets()->size() > 0) {

		unsigned int posicionEleccionAModificar = registroEleccionAModificar->getOffsets()->at(0);

		// analizo si son distintas las claves (si lo son, borro la vieja entidad e inserto la nueva entidad)
		if (claveDeUnicidadDeEleccionAModificar == claveDeUnicidadDeEleccionModificada) {

			unsigned int posicionEleccionModificada = this->elecciones->modificar(eleccionModificada,
					posicionEleccionAModificar);

			// si posicionEleccionModificada es distinta que la anterior, debo actualizar los indices de unicidad
			if (posicionEleccionModificada != posicionEleccionAModificar)
				this->indicePorUnicidad->modificar(claveDeUnicidadDeEleccionAModificar, posicionEleccionAModificar,
						posicionEleccionModificada);

			// actualizo los indices de clasificacion (borro y agrego)
			for (unsigned int i = 0; i < eleccionAModificar->getDistritos()->size(); i++) {
				string claveDistrito = eleccionAModificar->getDistritos()->at(i)->getNombre();
				string claveFecha = Utils::convertirEnteroAString(eleccionAModificar->getFecha());
				string claveDeDistritoYFecha = claveFecha + claveDistrito;
				indicePorDistritoYFecha->suprimir(claveDeDistritoYFecha, posicionEleccionAModificar);
			}

			for (unsigned int i = 0; i < eleccionModificada->getDistritos()->size(); i++) {
				string claveDistrito = eleccionModificada->getDistritos()->at(i)->getNombre();
				string claveFecha = Utils::convertirEnteroAString(eleccionModificada->getFecha());
				string claveDeDistritoYFecha = claveFecha + claveDistrito;
				indicePorDistritoYFecha->insertar(claveDeDistritoYFecha, posicionEleccionModificada);
			}

		} else {
			this->baja(eleccionAModificar);
			this->alta(eleccionModificada);
		}
		return true;
	} else
		return false;
}

bool ManejadorEleccion::existe(unsigned int fecha, string cargo) {

	string clave = Utils::convertirEnteroAString(fecha) + cargo;
	return this->indicePorUnicidad->existe(clave);
}

vector<Eleccion*>* ManejadorEleccion::recuperarEleccionesFechaYDistrito(string fecha, string distrito) {

	string clave = fecha + distrito;
	IRegistroIndice* registro = indicePorDistritoYFecha->buscar(clave);
	vector<Eleccion*>* elecciones = new vector<Eleccion*> ;
	if (registro != NULL && clave == registro->getClave()) {
		for (unsigned int i = 0; i < registro->getOffsets()->size(); i++) {
			Eleccion* nuevaEleccion = new Eleccion();
			this->elecciones->leer(nuevaEleccion, registro->getOffsets()->at(i));
			elecciones->push_back(nuevaEleccion);
		}
		delete registro;
	}
	return elecciones;
}

bool ManejadorEleccion::listarTodos(){
	bool toReturn = false;
	fstream txtFile;
	Configuracion* config = Configuracion::getInstancia();
	string path = config->getPathReportes() + "ListadoElecciones.txt";
	txtFile.open(path.c_str(), ios::out);
	if (txtFile.bad()) {
		txtFile.open(path.c_str(), ios::out);
	}
	txtFile << "Fecha		Cargo			Distritos" << endl;
	txtFile << "=================================================" << endl;

	vector<unsigned int>* offsets = this->indicePorUnicidad->getTodosLosDatos();
	if(!offsets->empty()){
		Eleccion* eleccion;
		for (unsigned int i = 0; i < offsets->size(); ++i) {
			eleccion = new Eleccion();
			this->elecciones->leer(eleccion, offsets->at(i));
//			mostrarDistritos(eleccion->getDistritos());
			txtFile << eleccion->getFecha() << "	"
					<< eleccion->getCargo()->getNombre() << "	";
			for (unsigned int i = 0; i < eleccion->getDistritos()->size(); ++i) {
					txtFile << eleccion->getDistritos()->at(i)->getNombre() << " ";
				}
			txtFile << endl;
			txtFile << "---------------------------------------------------------------------------------" << endl;
			txtFile << endl;
			delete eleccion;
		}

		toReturn = true;
		}else{
			toReturn = false;
		}
		txtFile.close();
		return toReturn;
}

void ManejadorEleccion::mostrarDistritos(vector<Distrito*>* distritos){

	for (unsigned int i = 0; i < distritos->size(); ++i) {
		cout << distritos->at(i)->getNombre() << "  ";
	}
	cout << endl;
}


ManejadorEleccion::~ManejadorEleccion() {
	delete this->elecciones;
	delete this->indicePorUnicidad;
	delete this->indicePorDistritoYFecha;
}

